#include"List.h"
//打印链表
void LTPrint(LTNode* phead)
{
    LTNode* pcur = phead->next;
    while (pcur != phead) {
        printf("%d->",pcur->data);
        pcur = pcur->next;
    }
    printf("......\n");
}
//申请节点
LTNode* LTBuyNode(LTDataType x)
{
    LTNode* newNode = (LTNode*)malloc(sizeof(LTNode));
    if (newNode == NULL) {
        perror("malloc fail");
        exit(1);
    }
    newNode->data = x;
    newNode->next = newNode->prev = newNode;
    return newNode;
}
//初始化
void LTInit(LTNode** pphead)
{
    //先申请一个头节点“哨兵位”
    *pphead = LTBuyNode(-1);
}
//尾插
void LTPushBack(LTNode* phead,LTDataType x)
{
    //断言一下，不能对无效指针插入
    assert(phead);
    //申请新节点
    LTNode* newnode = LTBuyNode(x);
    //先处理 newnode 的指针指向，因为其不会影响原链表的指向
    newnode->next = phead;
    newnode->prev = phead->prev;
    //然后改变 原尾节点 和 头节点
    phead->prev->next = newnode;
    phead->prev = newnode;
}
//头插
void LTPushFront(LTNode* phead,LTDataType x)
{
    assert(phead);
    LTNode* newnode = LTBuyNode(x);
    newnode->next = phead->next;
    newnode->prev = phead;
    //
    phead->next->prev = newnode;
    phead->next = newnode;
}
//判断链表是否为空
bool LTEmpty(LTNode* phead)
{
    assert(phead);
    //双链表为空时，头节点指向自身，返回 true
    return phead->next == phead;
}
//尾删
void LTPopBack(LTNode* phead)
{
    //头节点不能为空
    assert(phead);
    //双链表不能为空
    assert(!LTEmpty(phead));
    //保存一下原尾节点,最后释放掉尾节点
    LTNode* ret = phead->prev;
    //先改变 ret 前的节点的next，在改变 phead 的 prev
    phead->prev->prev->next = phead;
    phead->prev = phead->prev->prev;
    //最后释放并置空已经被保存的原尾节点的地址
    free(ret);
    ret = NULL;
}
//头删
void LTPopFront(LTNode* phead)
{
    assert(phead);
    assert(!LTEmpty(phead));
    LTNode* ret = phead->next;
    //
    ret->next->prev = phead;
    phead->next = ret->next;
    free(ret);
    ret = NULL;
}
//查找
LTNode* LTFind(LTNode* phead,LTDataType x)
{
    assert(phead);
    LTNode* pcur = phead->next;
    while (pcur != phead) {
        if (pcur->data == x) {
            return pcur;
        }
        pcur = pcur->next;
    }
    return NULL;
}
//在 pos 之后插入节点
void LTInsert(LTNode* pos,LTDataType x)
{
    assert(pos);
    LTNode* newnode = LTBuyNode(x);
    newnode->next = pos->next;
    newnode->prev = pos;
    //
    pos->next->prev = newnode;
    pos->next = newnode;
}
//删除pos 节点
void LTErase(LTNode* pos)
//传一级指针时，将 pos 置空无法改变 pos 在该函数外的空间是否为空。
//要想将 pos 节点在函数外也被置空，要传入二级指针，意为改变指向此节点的指针的值（将其置空）。
{
    assert(pos);
    pos->prev->next = pos->next;
    pos->next->prev = pos->prev;
    //
    free(pos);
    pos = NULL;//此时置空，是为了如果在该函数下，防止 pos 成为野指针被调用。
    //在函数外依旧是野指针，但是其在函数外被调用的概率不大，所以置不置空都问题不大。
}
//销毁双链表
void LTDestroy(LTNode** pphead)
{
    assert(pphead && *pphead);
    LTNode* pcur = (*pphead)->next;
    while (pcur != *pphead)
    {
        LTNode* Next = pcur->next;
        free(pcur);
        pcur = Next;
    }
    free(*pphead);
    *pphead = NULL;//此时直接在函数外也能置空
    pcur = NULL;
    //pcur置为空是为了规范，因为此时他已经成了野指针，
    //但是即使不置空也时没有关系的，因为此函数内没有继续的操作了。
}
//优化销毁链表函数接口
void LTDestroy2(LTNode* phead)
{
    assert(phead);
    LTNode* pcur = phead->next;
    while(pcur != phead)
    {
        LTNode* Next = pcur->next;//pcur 会被释放，所以要定义一个临时变量存储下一个节点。
        free(pcur);
        pcur = Next;
    }
    pcur = NULL;
}
//初始化优化接口
LTNode* LTInit2(void)
{
    //申请一个哨兵位
    LTNode* ret = LTBuyNode(-1);
    //一般传入一个无效值，例如“-1”
    return ret;
}
